<button @onclick="Run">Run common usage</button>

@foreach (var result in results)
{
    <div style="background-color: @(result.Value.passed ? "lightgreen" : "red");">
        <h2>@result.Key</h2>
        <span>@result.Value.result</span>
    </div>
}

@code {
    private readonly IDictionary<string, (bool passed, object result)> results = new Dictionary<string, (bool, object)>();

    [Parameter]
    public IDynamicJSProvider DynamicJSProvider { get; set; }

    private readonly (string description, object expected, Func<JSObject, Task<object>> operation)[] tests;

    public UsageCommon()
    {
        tests = new (string, object, Func<JSObject, Task<object>>)[]
        {
            ("Binary operator '+' (1 + 2)", 3, window =>
            {
                var a = JSObject.Create(window, 1);
                var b = JSObject.Create(window, 2);

                return DynamicJSProvider.Evaluate<int>(a + b);
            }),
            ("Binary operator '+' ('1' + 2)", "12", window =>
            {
                var a = JSObject.Create(window, "1");
                var b = JSObject.Create(window, 2);

                return DynamicJSProvider.Evaluate<string>(a + b);
            }),
            ("Binary operator '&' (42 & 79)", 10, window =>
            {
                var a = JSObject.Create(window, 42);
                var b = JSObject.Create(window, 79);

                return DynamicJSProvider.Evaluate<int>(a & b);
            }),
            ("Binary operator '&=' (a = 42, a &= 79)", 10, window =>
            {
                var a = JSObject.Create(window, 42);
                var b = JSObject.Create(window, 79);
                a &= b;

                return DynamicJSProvider.Evaluate<int>(a);
            }),
            ("Binary operator '/' (7 / 2)", 3.5f, window =>
            {
                var a = JSObject.Create(window, 7);
                var b = JSObject.Create(window, 2);

                return DynamicJSProvider.Evaluate<float>(a / b);
            }),
            ("Binary operator '/=' (a = 7, a /= 2)", 3.5f, window =>
            {
                var a = JSObject.Create(window, 7);
                var b = JSObject.Create(window, 2);
                a /= b;

                return DynamicJSProvider.Evaluate<float>(a);
            }),
            ("Binary operator '^' (42 ^ 79)", 101, window =>
            {
                var a = JSObject.Create(window, 42);
                var b = JSObject.Create(window, 79);

                return DynamicJSProvider.Evaluate<int>(a ^ b);
            }),
            ("Binary operator '^=' (a = 42, a ^= 79)", 101, window =>
            {
                var a = JSObject.Create(window, 42);
                var b = JSObject.Create(window, 79);
                a ^= b;

                return DynamicJSProvider.Evaluate<int>(a);
            }),
            ("Binary operator '>' (2 > 1)", true, window =>
            {
                var a = JSObject.Create(window, 2);
                var b = JSObject.Create(window, 1);

                return DynamicJSProvider.Evaluate<bool>(a > b);
            }),
            ("Binary operator '>' (2 > 2)", false, window =>
            {
                var a = JSObject.Create(window, 2);
                var b = JSObject.Create(window, 2);

                return DynamicJSProvider.Evaluate<bool>(a > b);
            }),
            ("Binary operator '>=' (2 >= 1)", true, window =>
            {
                var a = JSObject.Create(window, 2);
                var b = JSObject.Create(window, 1);

                return DynamicJSProvider.Evaluate<bool>(a >= b);
            }),
            ("Binary operator '>=' (2 >= 2)", true, window =>
            {
                var a = JSObject.Create(window, 2);
                var b = JSObject.Create(window, 2);

                return DynamicJSProvider.Evaluate<bool>(a >= b);
            }),
            ("Binary operator '>=' (1 >= 2)", false, window =>
            {
                var a = JSObject.Create(window, 1);
                var b = JSObject.Create(window, 2);

                return DynamicJSProvider.Evaluate<bool>(a >= b);
            }),
            ("Binary operator '<<' (1 << 3)", 8, window =>
            {
                var a = JSObject.Create(window, 1);
                var b = JSObject.Create(window, 3);

                return DynamicJSProvider.Evaluate<int>(a << b);
            }),
            ("Binary operator '<<=' (a = 1, a <<= 3)", 8, window =>
            {
                var a = JSObject.Create(window, 1);
                var b = JSObject.Create(window, 3);
                a <<= b;

                return DynamicJSProvider.Evaluate<int>(a);
            }),
            ("Binary operator '<' (1 > 2)", true, window =>
            {
                var a = JSObject.Create(window, 1);
                var b = JSObject.Create(window, 2);

                return DynamicJSProvider.Evaluate<bool>(a < b);
            }),
            ("Binary operator '<' (2 < 2)", false, window =>
            {
                var a = JSObject.Create(window, 2);
                var b = JSObject.Create(window, 2);

                return DynamicJSProvider.Evaluate<bool>(a < b);
            }),
            ("Binary operator '<=' (1 <= 2)", true, window =>
            {
                var a = JSObject.Create(window, 1);
                var b = JSObject.Create(window, 2);

                return DynamicJSProvider.Evaluate<bool>(a <= b);
            }),
            ("Binary operator '<=' (2 <= 2)", true, window =>
            {
                var a = JSObject.Create(window, 2);
                var b = JSObject.Create(window, 2);

                return DynamicJSProvider.Evaluate<bool>(a <= b);
            }),
            ("Binary operator '<=' (2 <= 1)", false, window =>
            {
                var a = JSObject.Create(window, 2);
                var b = JSObject.Create(window, 1);

                return DynamicJSProvider.Evaluate<bool>(a <= b);
            }),
            ("Binary operator '%' (6 % 4)", 2, window =>
            {
                var a = JSObject.Create(window, 6);
                var b = JSObject.Create(window, 4);

                return DynamicJSProvider.Evaluate<int>(a % b);
            }),
            ("Binary operator '%=' (a = 6, a %= 4)", 2, window =>
            {
                var a = JSObject.Create(window, 6);
                var b = JSObject.Create(window, 4);
                a %= b;

                return DynamicJSProvider.Evaluate<int>(a);
            }),
            ("Binary operator '*' (8 * 3)", 24, window =>
            {
                var a = JSObject.Create(window, 8);
                var b = JSObject.Create(window, 3);

                return DynamicJSProvider.Evaluate<int>(a * b);
            }),
            ("Binary operator '*=' (a = 8, a *= 3)", 24, window =>
            {
                var a = JSObject.Create(window, 8);
                var b = JSObject.Create(window, 3);
                a *= b;

                return DynamicJSProvider.Evaluate<int>(a);
            }),
            ("Binary operator '==' (3 == 3, or 3 === 3 in JS)", true, window =>
            {
                var a = JSObject.Create(window, 3);
                var b = JSObject.Create(window, 3);

                return DynamicJSProvider.Evaluate<bool>(a == b);
            }),
            ("Binary operator '==' (3 == '3', or 3 === '3' in JS)", false, window =>
            {
                var a = JSObject.Create(window, 3);
                var b = JSObject.Create(window, "3");

                return DynamicJSProvider.Evaluate<bool>(a == b);
            }),
            ("Binary operator '==' (Reference equality, === in JS)", true, window =>
            {
                var a = JSObject.Create(window, new
                {
                    value = "String value",
                    nested = new
                    {
                        value = 1
                    }
                });
                var b = a;

                return DynamicJSProvider.Evaluate<bool>(a == b);
            }),
            ("Binary operator '==' (Reference inequality, === in JS)", false, window =>
            {
                var a = JSObject.Create(window, new
                {
                    value = "String value",
                    nested = new
                    {
                        value = 1
                    }
                });
                var b = JSObject.Create(window, new
                {
                    value = "String value",
                    nested = new
                    {
                        value = 1
                    }
                });

                return DynamicJSProvider.Evaluate<bool>(a == b);
            }),
            ("Binary operator '!=' (3 != 3, or 3 !== 3 in JS)", false, window =>
            {
                var a = JSObject.Create(window, 3);
                var b = JSObject.Create(window, 3);

                return DynamicJSProvider.Evaluate<bool>(a != b);
            }),
            ("Binary operator '==' (3 == '3', or 3 === '3' in JS)", true, window =>
            {
                var a = JSObject.Create(window, 3);
                var b = JSObject.Create(window, "3");

                return DynamicJSProvider.Evaluate<bool>(a != b);
            }),
            ("Binary operator '!=' (Reference equality, !== in JS)", false, window =>
            {
                var a = JSObject.Create(window, new
                {
                    value = "String value",
                    nested = new
                    {
                        value = 1
                    }
                });
                var b = a;

                return DynamicJSProvider.Evaluate<bool>(a != b);
            }),
            ("Binary operator '!=' (Reference inequality, !== in JS)", true, window =>
            {
                var a = JSObject.Create(window, new
                {
                    value = "String value",
                    nested = new
                    {
                        value = 1
                    }
                });
                var b = JSObject.Create(window, new
                {
                    value = "String value",
                    nested = new
                    {
                        value = 1
                    }
                });

                return DynamicJSProvider.Evaluate<bool>(a != b);
            }),
            ("Binary operator '|' (42 | 79)", 111, window =>
            {
                var a = JSObject.Create(window, 42);
                var b = JSObject.Create(window, 79);

                return DynamicJSProvider.Evaluate<int>(a | b);
            }),
            ("Binary operator '|=' (a = 42, a |= 79)", 111, window =>
            {
                var a = JSObject.Create(window, 42);
                var b = JSObject.Create(window, 79);
                a |= b;

                return DynamicJSProvider.Evaluate<int>(a);
            }),
            ("Binary operator '>>' (32 >> 3)", 4, window =>
            {
                var a = JSObject.Create(window, 32);
                var b = JSObject.Create(window, 3);

                return DynamicJSProvider.Evaluate<int>(a >> b);
            }),
            ("Binary operator '>>=' (a = 32, a >>= 3)", 4, window =>
            {
                var a = JSObject.Create(window, 32);
                var b = JSObject.Create(window, 3);
                a >>= b;

                return DynamicJSProvider.Evaluate<int>(a);
            }),
            ("Binary operator '-' (5 - 3)", 2, window =>
            {
                var a = JSObject.Create(window, 5);
                var b = JSObject.Create(window, 3);

                return DynamicJSProvider.Evaluate<int>(a - b);
            }),
            ("Binary operator '-=' (a = 5, a -= 3)", 2, window =>
            {
                var a = JSObject.Create(window, 5);
                var b = JSObject.Create(window, 3);
                a -= b;

                return DynamicJSProvider.Evaluate<int>(a);
            }),
            ("Unary operator '--' (a = 4, a--)", 4, window =>
            {
                var a = JSObject.Create(window, 4);

                return DynamicJSProvider.Evaluate<int>(a--);
            }),
            ("Unary operator '--' (a = 4, --a)", 3, window =>
            {
                var a = JSObject.Create(window, 4);

                return DynamicJSProvider.Evaluate<int>(--a);
            }),
            ("Unary operator '++' (a = 4, a++)", 4, window =>
            {
                var a = JSObject.Create(window, 4);

                return DynamicJSProvider.Evaluate<int>(a++);
            }),
            ("Unary operator '++' (a = 4, ++a)", 5, window =>
            {
                var a = JSObject.Create(window, 4);

                return DynamicJSProvider.Evaluate<int>(++a);
            }),
            ("Unary operator '-' (a = 2, -a)", -2, window =>
            {
                var a = JSObject.Create(window, 2);

                return DynamicJSProvider.Evaluate<int>(-a);
            }),
            ("Unary operator '!' (a = true, !a)", false, window =>
            {
                var a = JSObject.Create(window, true);

                return DynamicJSProvider.Evaluate<bool>(!a);
            }),
            ("Unary operator '~' (a = 79, ~a)", -80, window =>
            {
                var a = JSObject.Create(window, 79);

                return DynamicJSProvider.Evaluate<int>(~a);
            }),
            ("Unary operator '+' (a = '9', +a)", 9, window =>
            {
                var a = JSObject.Create(window, "9");

                return DynamicJSProvider.Evaluate<int>(+a);
            }),
        };
    }

    private async Task Run()
    {
        results.Clear();

        foreach (var (name, expected, operation) in tests)
        {
            var result = await DynamicJSProvider.RunWithWindow(operation);
            var passed = expected.Equals(result);

            results[name] = (passed, result);
        }
    }
}
